﻿using Engine;
using Engine.Graphics;
using System;
using System.Collections.Generic;
using System.Linq;
namespace SCPAK2
{
    public static class ScreensManager
    {
        public class AnimationData
        {
            public Screen OldScreen;

            public Screen NewScreen;

            public float Factor;

            public float Speed;

            public object[] Parameters;
        }

        public static Dictionary<string, Screen> m_screens = new Dictionary<string, Screen>();

        public static AnimationData m_animationData;

        public static PrimitivesRenderer2D m_pr2 = new PrimitivesRenderer2D();

        public static PrimitivesRenderer3D m_pr3 = new PrimitivesRenderer3D();

        public static Engine.Random Random = new Engine.Random(0);

        public static RenderTarget2D m_uiRenderTarget;

        public static Vector3 m_vrQuadPosition;

        public static Matrix m_vrQuadMatrix;

        public static float DebugUiScale = 1f;

        public static ContainerWidget RootWidget
        {
            get;
            set;
        }

        public static bool IsAnimating => m_animationData != null;

        public static Screen CurrentScreen
        {
            get;
            set;
        }

        public static Screen PreviousScreen
        {
            get;
            set;
        }

        public static T FindScreen<T>(string name) where T : Screen
        {
            m_screens.TryGetValue(name, out Screen value);
            return (T)value;
        }

        public static void AddScreen(string name, Screen screen)
        {
            m_screens.Add(name, screen);
        }

        public static void SwitchScreen(string name, params object[] parameters)
        {
            SwitchScreen(string.IsNullOrEmpty(name) ? null : FindScreen<Screen>(name), parameters);
        }

        public static void SwitchScreen(Screen screen, params object[] parameters)
        {
            if (m_animationData != null)
            {
                EndAnimation();
            }
            m_animationData = new AnimationData
            {
                NewScreen = screen,
                OldScreen = CurrentScreen,
                Parameters = parameters,
                Speed = ((CurrentScreen == null) ? float.MaxValue : 4f)
            };
            if (CurrentScreen != null)
            {
                RootWidget.IsUpdateEnabled = false;
                CurrentScreen.Input.Clear();
            }
            PreviousScreen = CurrentScreen;
            CurrentScreen = screen;
            UpdateAnimation();
            if (CurrentScreen != null)
            {
                Log.Verbose($"Entered screen \"{GetScreenName(CurrentScreen)}\"");
            }
        }

        public static void Initialize()
        {
            RootWidget = new CanvasWidget();
            RootWidget.WidgetsHierarchyInput = new WidgetInput();
            InitScreens();
            SwitchScreen("ModelView");
        }

        public static void InitScreens()
        {
            AddScreen("ModelView",new ModelScreen());
        }


        public static void Update()
        {
            if (RootWidget == null)
            {
                Initialize();
            }
            if (m_animationData != null)
            {
                UpdateAnimation();
            }
            Widget.UpdateWidgetsHierarchy(RootWidget);
        }

        public static void Draw()
        {
            Utilities.Dispose(ref m_uiRenderTarget);
            LayoutAndDrawWidgets();
        }

        public static void UpdateAnimation()
        {
            float num = MathUtils.Min(Time.FrameDuration, 0.1f);
            float factor = m_animationData.Factor;
            m_animationData.Factor = MathUtils.Min(m_animationData.Factor + m_animationData.Speed * num, 1f);
            if (m_animationData.Factor < 0.5f)
            {
                if (m_animationData.OldScreen != null)
                {
                    float num2 = 2f * (0.5f - m_animationData.Factor);
                    float scale = 1f;
                    m_animationData.OldScreen.ColorTransform = new Color(num2, num2, num2, num2);
                    m_animationData.OldScreen.RenderTransform = Matrix.CreateTranslation((0f - m_animationData.OldScreen.ActualSize.X) / 2f, (0f - m_animationData.OldScreen.ActualSize.Y) / 2f, 0f) * Matrix.CreateScale(scale) * Matrix.CreateTranslation(m_animationData.OldScreen.ActualSize.X / 2f, m_animationData.OldScreen.ActualSize.Y / 2f, 0f);
                }
            }
            else if (factor < 0.5f)
            {
                if (m_animationData.OldScreen != null)
                {
                    m_animationData.OldScreen.Leave();
                    RootWidget.Children.Remove(m_animationData.OldScreen);
                }
                if (m_animationData.NewScreen != null)
                {
                    RootWidget.Children.Insert(0, m_animationData.NewScreen);
                    m_animationData.NewScreen.Enter(m_animationData.Parameters);
                    m_animationData.NewScreen.ColorTransform = Color.Transparent;
                    RootWidget.IsUpdateEnabled = true;
                }
            }
            else if (m_animationData.NewScreen != null)
            {
                float num3 = 2f * (m_animationData.Factor - 0.5f);
                float scale2 = 1f;
                m_animationData.NewScreen.ColorTransform = new Color(num3, num3, num3, num3);
                m_animationData.NewScreen.RenderTransform = Matrix.CreateTranslation((0f - m_animationData.NewScreen.ActualSize.X) / 2f, (0f - m_animationData.NewScreen.ActualSize.Y) / 2f, 0f) * Matrix.CreateScale(scale2) * Matrix.CreateTranslation(m_animationData.NewScreen.ActualSize.X / 2f, m_animationData.NewScreen.ActualSize.Y / 2f, 0f);
            }
            if (m_animationData.Factor >= 1f)
            {
                EndAnimation();
            }
        }

        public static void EndAnimation()
        {
            if (m_animationData.NewScreen != null)
            {
                m_animationData.NewScreen.ColorTransform = Color.White;
                m_animationData.NewScreen.RenderTransform = Matrix.CreateScale(1f);
            }
            m_animationData = null;
        }

        public static string GetScreenName(Screen screen)
        {
            string key = m_screens.FirstOrDefault((KeyValuePair<string, Screen> kvp) => kvp.Value == screen).Key;
            if (key == null)
            {
                return string.Empty;
            }
            return key;
        }
        public static void LayoutAndDrawWidgets()
        {
            Display.Clear(Color.Black, 1f, 0);
            float num = 1120f;
            var vector = new Vector2(Display.Viewport.Width, Display.Viewport.Height);
            float num2 = vector.X / num;
            var availableSize = new Vector2(num, num / vector.X * vector.Y);
            float num3 = num * 9f / 16f;
            if (vector.Y / num2 < num3)
            {
                num2 = vector.Y / num3;
                availableSize = new Vector2(num3 / vector.Y * vector.X, num3);
            }
            RootWidget.LayoutTransform = Matrix.CreateScale(num2, num2, 1f);
            Widget.LayoutWidgetsHierarchy(RootWidget, availableSize);
            Widget.DrawWidgetsHierarchy(RootWidget);
        }

        public static void QueueQuad(FlatBatch3D batch, Vector3 corner, Vector3 right, Vector3 up, Color color)
        {
            Vector3 p = corner + right;
            Vector3 p2 = corner + right + up;
            Vector3 p3 = corner + up;
            batch.QueueQuad(corner, p, p2, p3, color);
        }

        public static void QueueQuad(TexturedBatch3D batch, Vector3 center, Vector3 right, Vector3 up, Color color)
        {
            QueueQuad(batch, center, right, up, color, new Vector2(0f, 0f), new Vector2(1f, 1f));
        }

        public static void QueueQuad(TexturedBatch3D batch, Vector3 corner, Vector3 right, Vector3 up, Color color, Vector2 tc1, Vector2 tc2)
        {
            Vector3 p = corner + right;
            Vector3 p2 = corner + right + up;
            Vector3 p3 = corner + up;
            batch.QueueQuad(corner, p, p2, p3, new Vector2(tc1.X, tc2.Y), new Vector2(tc2.X, tc2.Y), new Vector2(tc2.X, tc1.Y), new Vector2(tc1.X, tc1.Y), color);
        }
    }
}
